home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Libris Britannia 4
/
science library(b).zip
/
science library(b)
/
DDJMAG
/
DDJ9203.ZIP
/
BLACKBRD.ASC
< prev
next >
Wrap
Text File
|
1992-01-24
|
18KB
|
536 lines
_PROGRAMMING WITH COMMUNCIATION PROTOCOL STACKS_
by Gordon Free
[LISTING ONE]
#ifndef FT_H
#define FT_H
#define HVC_FIRST 2
#define HVC_LAST 5
#define MAX_VCS HVC_LAST-HVC_FIRST+1
#define HDRSIZE MAX_APPHDRDATA+sizeof(BBHDR)
/* Message command values */
#define FT2_SEND 3
#define FT2_RECEIVE 4
/* Bit fields for Blackbird events */
typedef union {
struct {
unsigned ListenCallback : 1;
unsigned ConnectCallback : 1;
unsigned ReadBreathe : 1;
unsigned ReadCallback : 1;
unsigned WriteBreathe : 1;
unsigned WriteCallback : 1;
unsigned DisconnectCallback : 1;
} flags;
int all;
} EVENT_T;
/* Structure for info on currently open file */
typedef struct _FILEDATA {
FILE *hStream; /* stream handle */
char *pszName; /* name of file */
char *pszOpenMode; /* mode file is opened in "r", "w", etc. */
long lSize; /* size of file in bytes */
void *pvBuffer; /* ptr to buffer of file contents */
} FILEDATA_T;
/* Structure for application service, one per VC */
typedef struct _SVCDATA {
FILEDATA_T fdCurFile; /* current file info */
char bbhXmit[HDRSIZE]; /* BB hdr for sending */
char bbhRcv[HDRSIZE]; /* BB hdr for rcving */
char *pszRemoteName; /* name of remote machine */
long lBytesSoFar; /* num bytes xferred */
int fActive; /* TRUE if VC is active */
short sStatus; /* status of last BB event */
EVENT_T fEvent; /* BB event flags */
} SVCDATA_T;
/*----- Callback routine prototypes ------*/
void cbRemService (
unsigned usNumSvcs /* Number of remote services */
);
SHORT cbListen (
HANDLE hVC, /* Virtual connection handle */
ULONG ul1, /* Nothing at this time */
ULONG ul2 /* Status = SHORT1FROMUL( ul2 ) */
);
SHORT cbConnect (
HANDLE hVC, /* Virtual connection handle */
ULONG ul1, /* Nothing at this time */
ULONG ul2 /* Status = SHORT1FROMUL( ul2 ) */
);
SHORT cbDisConnect (
HANDLE hVC, /* Virtual connection handle */
ULONG ul1, /* Nothing at this time */
ULONG ul2 /* Status = SHORT1FROMUL( ul2 ) */
);
SHORT cbRead (
HANDLE hVC, /* Virtual connection handle */
ULONG ul1, /* Number of bytes read */
ULONG ul2 /* Status = SHORT1FROMUL( ul2 ) */
);
SHORT cbWrite (
HANDLE hVC, /* Virtual connection handle */
ULONG ul1, /* Number of bytes sent */
ULONG ul2 /* Status = SHORT1FROMUL( ul2 ) */
);
#endif
[LISTING TWO]
/*====================================================================
(c) Copyright 1991, Gordon Free
All Rights Reserved.
--------------------------------------------------------------------
Filename: FT.C
Project: DDJ Article
$Author$
$Revision$
$Date$
Purpose: Sample file transfer program written for Blackbird API.
====================================================================*/
/*----- Includes ------*/
#include <stdio.h>
#include <conio.h>
#include <malloc.h>
#include <string.h>
#include <dos.h>
#include <fcntl.h>
#include <io.h>
#include <sys\types.h>
#include <sys\stat.h>
#include "vcapi.h"
#include "ft.h"
/*----- Local Defines and Typedefs ------ */
#define ESC 0x1B
#define BUFF_SIZE (64*1024-1)
/*------ Global Variables -----*/
int fUpdateServices=FALSE; /* remote service list has changed */
HANDLE hvcServer=HVC_NONE; /* vc handle of remote server */
SVCDATA_T svc[MAX_VCS]; /* array of app service info */
char acMachineName[MAX_MACHID] = "Unknown";
/*---- DisplayServices: prints a report of all available remote services ----*/
void DisplayServices(void)
{
int nServices; /* num of services reported */
REMSERVICES remserv; /* service info struct */
static HANDLE ahRS[10]; /* array of remote svc handles */
int i;
puts("\nList of Remote Machines ...");
puts("---------------------------");
/* Fill in array of remote service handles */
nServices = vcQuery(ahRS, HBOUND(ahRS));
/* Report service handle and machine name for each remote service */
for (i=0; i<nServices; i++) {
sGetRemSvc(ahRS[i], &remserv);
printf(" %d) %s on %s %c\n", ahRS[i], remserv.acMachineName
, remserv.acPortName
, remserv.fInUse ? '*' : ' ');
}
}
/*-- SendFile: read specified file and hand it to Blackbird for delivery --*/
size_t SendFile (
HANDLE vch, /* handle of virtual connection */
char *name /* name of file */
)
{
int size=0; /* number of bytes read */
int fileOut; /* file stream to read from */
PBBHDR pbbhXmit; /* ptr to BB header */
SVCDATA_T *psvc; /* ptr to service struct for this vc */
printf("Sending %s ...\n", name);
fileOut = open(name,O_RDONLY|O_BINARY);
if (fileOut > 0) {
psvc = &svc[vch-HVC_FIRST];
/* Read contents of file into buffer */
size = read(fileOut, psvc->fdCurFile.pvBuffer, BUFF_SIZE);
close(fileOut);
/* Put name into packet header */
pbbhXmit = (PBBHDR)&(psvc->bbhXmit[0]);
strcpy(&(pbbhXmit->bAppData[1]), name);
/* Indicate what remote is to do with this data */
pbbhXmit->bAppData[0] = FT2_RECEIVE;
pbbhXmit->ubBytesToFollow = strlen(name)+2;
vcWrite(vch,pbbhXmit, psvc->fdCurFile.pvBuffer, size
, NULL, cbWrite, TWO_SECS);
} else {
perror("Error opening file");
}
return size;
}
/*----SaveFile: write contents of buffer into file with specified name----*/
int SaveFile (
char *name,
long lsize,
void far *buffer
)
{
int size;
int fileIn;
printf("Saved file = %s\n", name);
fileIn = open(name,O_WRONLY|O_CREAT|O_TRUNC|O_BINARY);
if (fileIn > 0) {
size = (size_t) lsize;
write(fileIn, buffer, size);
close(fileIn);
} else {
perror("Error saving file");
}
return 0;
}
/*---CheckEvents: polls each virtual connection looking for events that
have been flagged by the various callback routines.---*/
void CheckEvents ( void )
{
EVENT_T evt;
SVCDATA_T *psvc;
PBBHDR pbbhRcv;
HANDLE vch;
void *buff;
int i;
/* Loop through all possible virtual connections */
for (i=0, psvc=svc; i<MAX_VCS; i++, psvc++) {
/* Check to see if anything happened */
if (psvc->fEvent.all) {
/* Get copy of event flags and then reset them. This is done with
/* interrupts disabled so that we don't miss any events. */
_disable();
evt = psvc->fEvent;
psvc->fEvent.all = FALSE;
_enable();
/* ------------------- Listen --------------------------- */
/* Somebody connected to us, allocate storage and issue a */
/* read to get file transfer requests. */
if (evt.flags.ListenCallback) {
puts("#Listen Callback");
pbbhRcv = (PBBHDR)&(psvc->bbhRcv[0]);
if (psvc->fdCurFile.pvBuffer != NULL) {
vcRead(HVC_FIRST+i,pbbhRcv, psvc->fdCurFile.pvBuffer
, BUFF_SIZE, NULL, cbRead, TWO_SECS);
} else {
puts("Error allocating memory");
}
/* Register a new service for use by other clients */
buff = malloc(BUFF_SIZE);
if (buff != NULL) {
vch = vcListen ("FXFR","DDJ", cbListen, cbDisConnect);
svc[vch-HVC_FIRST].fdCurFile.pvBuffer = buff;
} else {
puts("Error allocating memory");
}
}
/* ------------------- Connect -------------------------- */
/* We've successfully connected to a remote server */
if (evt.flags.ConnectCallback) {
puts("#Connect Callback");
hvcServer = HVC_FIRST+i;
}
/* ------------------- Read --------------------------- */
/* We've gotten a request, so process it! */
if ((evt.flags.ReadCallback) && (psvc->sStatus == 0)) {
pbbhRcv = (PBBHDR)&(psvc->bbhRcv[0]);
/* Is it a request to receive a file? */
if (pbbhRcv->bAppData[0] == FT2_RECEIVE) {
SaveFile(&(pbbhRcv->bAppData[1]), psvc->lBytesSoFar
, psvc->fdCurFile.pvBuffer);
/* How about send a file? */
} else if (pbbhRcv->bAppData[0] == FT2_SEND) {
SendFile(i+HVC_FIRST, &(pbbhRcv->bAppData[1]));
/* No comprende */
} else {
puts("Huh?");
}
vcRead(HVC_FIRST+i,pbbhRcv, psvc->fdCurFile.pvBuffer
, BUFF_SIZE, NULL, cbRead, TWO_SECS);
}
/* ------------------- Write --------------------------- */
if ((evt.flags.WriteCallback) && (psvc->sStatus == 0)) {
puts("#Write Complete");
}
/* ------------------- Disconnect ---------------------- */
/* Remote went byebye */
if (evt.flags.DisconnectCallback) {
puts("#Disconnect Callback");
free(psvc->fdCurFile.pvBuffer);
if (i+HVC_FIRST == hvcServer)
hvcServer = HVC_NONE;
}
}
}
if (fUpdateServices) {
fUpdateServices = FALSE;
DisplayServices();
}
}
/*---DoUserRequests: check keyboard for activity and process user's
command. Returns TRUE if user has not requested to exit.---*/
int DoUserRequests ( void )
{
HANDLE vch;
SVCDATA_T *psvc;
PBBHDR pbbhXmit, pbbhRcv;
int fContinue=TRUE;
char filename[80];
void *buff;
int c;
if ( kbhit() ) {
switch (c = getch()) {
/* ------------------- Exit ----------------------------- */
case ESC:
fContinue = FALSE;
break;
/* ------------------- Connect -------------------------- */
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
/* Disconnect from current server, if any. */
/* Buffer will be released when disconnect completes */
if (hvcServer != HVC_NONE) {
vcDisconnect(hvcServer);
}
/* Allocate buffer for new service */
buff = malloc(BUFF_SIZE);
if (buff != NULL) {
/* Connect to remote server */
vch = vcConnect(c-'0', cbConnect, cbDisConnect, TWO_SECS);
svc[vch-HVC_FIRST].fdCurFile.pvBuffer = buff;
} else {
puts("Error allocating memory");
}
break;
/* ------------------- Send File ------------------------ */
case 's':
case 'S':
if (hvcServer != HVC_NONE) {
psvc = &svc[hvcServer-HVC_FIRST];
printf("\nEnter name of file to send >");
scanf("%s", filename);
SendFile(hvcServer, filename);
} else {
puts("You must establish a connection first!");
}
break;
/* ------------------- Receive File --------------------- */
case 'r':
case 'R':
if (hvcServer != HVC_NONE) {
psvc = &svc[hvcServer-HVC_FIRST];
/* Set up ptrs to BB hdrs for receive and send */
pbbhXmit = (PBBHDR)&(psvc->bbhXmit[0]);
pbbhRcv = (PBBHDR)&(psvc->bbhRcv[0]);
/* Instruct remote server to send specified file */
printf("\nEnter name of file to receive >");
scanf("%s", &(pbbhXmit->bAppData[1]));
pbbhXmit->bAppData[0] = FT2_SEND;
pbbhXmit->ubBytesToFollow
= strlen(&(pbbhXmit->bAppData[1]))+2;
/* Post read before sending request so that we are ready */
/* for response */
vcRead(hvcServer,pbbhRcv, psvc->fdCurFile.pvBuffer
, BUFF_SIZE, NULL, cbRead, TWO_SECS);
/* Send request for file */
vcWrite(hvcServer,pbbhXmit, NULL, 0, NULL, cbWrite, TWO_SECS);
} else {
puts("You must establish a connection first!");
}
default:
break;
}
}
return fContinue;
}
/*----main: initalize Blackbird and alternate between processing Blackbird
events and user requests. ----*/
int main (
int argc,
char **argv
)
{
HANDLE vch;
void *buff;
puts("Blackbird File Transfer Sample Program ver 1.0");
puts(" (c) Copyright 1991, Gordon Free.");
puts(" All Rights Reserved.\n");
puts(vcVersion());
/* Parse machine name off command line */
if (argc >= 2) {
strncpy(acMachineName, argv[1], sizeof(acMachineName-1));
acMachineName[sizeof(acMachineName-1)] = '\0';
}
/* Initialize Blackbird and request notification of remote services */
vcInit(acMachineName,"DDJ");
vcRemsvcUpdate(cbRemService);
/* Register as a server only if user gave a machine name */
if (argc >= 2) {
buff = malloc(BUFF_SIZE);
if (buff != NULL) {
vch = vcListen ("FXFR","DDJ", cbListen, cbDisConnect);
svc[vch-HVC_FIRST].fdCurFile.pvBuffer = buff;
} else {
puts("Error allocating memory");
goto finish;
}
}
/* Alternate between checking for Blackbird events and processing
user requests. */
do
{
CheckEvents();
} while (DoUserRequests());
finish:
puts("Exiting ...");
vcEnd();
return 0;
}
[LISTING THREE]
/*--------------------------------------------------------------------
(c) Copyright 1991, Gordon Free
All Rights Reserved.
====================================================================
Filename: FT_CB.C
Project: DDJ Article
$Author$
$Revision$
$Date$
Purpose: Callback routines for Blackbird events
====================================================================*/
/*-----Includes-----*/
#include <stdio.h>
#include "vcapi.h"
#include "ft.h"
/*------Global Variables ------*/
extern SVCDATA_T svc[MAX_VCS]; /* service info for each VC */
extern int fUpdateServices; /* set TRUE to display remotes */
/* These routines are called at interrupt time, so no stack checking! */
#pragma check_stack(off)
/* Called whenever remote service list changes */
void cbRemService (
unsigned usNumSvcs /* Number of remote services */
)
{
fUpdateServices = TRUE;
}
/* Called when remote machine connects to us as a client */
SHORT cbListen (
HANDLE hVC, /* Virtual connection handle */
ULONG ul1, /* Nothing at this time */
ULONG ul2 /* Status = SHORT1FROMUL( ul2 ) */
)
{
svc[hVC-HVC_FIRST].fEvent.flags.ListenCallback = TRUE;
svc[hVC-HVC_FIRST].sStatus = SHORT1FROMULONG(ul2);
svc[hVC-HVC_FIRST].fActive = TRUE;
return (FALSE);
}
/* Called when remote server acknowledges our connection request */
SHORT cbConnect (
HANDLE hVC, /* Virtual connection handle */
ULONG ul1, /* Nothing at this time */
ULONG ul2 /* Status = SHORT1FROMUL( ul2 ) */
)
{
svc[hVC-HVC_FIRST].fEvent.flags.ConnectCallback = TRUE;
svc[hVC-HVC_FIRST].sStatus = SHORT1FROMULONG(ul2);
svc[hVC-HVC_FIRST].fActive = TRUE;
return (FALSE);
}
/* Called anytime a VC is broken */
SHORT cbDisConnect (
HANDLE hVC, /* Virtual connection handle */
ULONG ul1, /* Nothing at this time */
ULONG ul2 /* Status = SHORT1FROMUL( ul2 ) */
)
{
svc[hVC-HVC_FIRST].fEvent.flags.DisconnectCallback = TRUE;
svc[hVC-HVC_FIRST].fActive = FALSE;
return (FALSE);
}
/* Called when we've receive a data buffer from remote */
SHORT cbRead (
HANDLE hVC, /* Virtual connection handle */
ULONG ul1, /* Number of bytes received */
ULONG ul2 /* Status = SHORT1FROMUL( ul2 ) */
)
{
svc[hVC-HVC_FIRST].fEvent.flags.ReadCallback = TRUE;
svc[hVC-HVC_FIRST].lBytesSoFar = ul1;
svc[hVC-HVC_FIRST].sStatus = SHORT1FROMULONG(ul2);
return (FALSE);
}
/* Called when data has been successfully sent to remote */
SHORT cbWrite (
HANDLE hVC, /* Virtual connection handle */
ULONG ul1, /* Nothing at this time */
ULONG ul2 /* Status = SHORT1FROMUL( ul2 ) */
)
{
svc[hVC-HVC_FIRST].fEvent.flags.WriteCallback = TRUE;
svc[hVC-HVC_FIRST].sStatus = SHORT1FROMULONG(ul2);
return (FALSE);
}
#pragma check_stack()